home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / smail-3.1.28 / util / mkdbm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-11  |  10.0 KB  |  504 lines

  1. /* @(#)util/mkdbm.c    1.8 7/11/92 11:40:03 */
  2.  
  3. /*
  4.  *    Copyright (C) 1987, 1988 Ronald S. Karr and Landon Curt Noll
  5.  *    Copyright (C) 1992  Ronald S. Karr
  6.  * 
  7.  * See the file COPYING, distributed with smail, for restriction
  8.  * and warranty information.
  9.  */
  10.  
  11. /*
  12.  * mkdbm.c:
  13.  *    Take a list of lines with a key followed by a colon character
  14.  *    or white space followed by data and build a dbm database from
  15.  *    them.  If the flag -f is given, downcase the keys.
  16.  *
  17.  *    Usage:  mkdbm [-o database] [-fvndy] [input_file ...]
  18.  */
  19. #include <stdio.h>
  20. #include <ctype.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include "defs.h"
  24. #include "smail.h"
  25. #include "dys.h"
  26. #include "exitcodes.h"
  27. #include "dbm_compat.h"
  28. #ifndef DEPEND
  29. # include "extern.h"
  30. #endif
  31.  
  32. #if !defined(HAVE_GETHOSTNAME) && defined(HAVE_UNAME)
  33. #include <sys/utsname.h>
  34. #endif
  35.  
  36. char *program;                /* argv[0] from main */
  37. /* variables local to this file */
  38. static char *out_name = NULL;
  39. static char *temp_dir = NULL;
  40. static char *temp_pag = NULL;
  41. static int downcase = FALSE;
  42. static int ypstamps = FALSE;
  43. static int verbose = FALSE;
  44. static int no_at_record = FALSE;
  45. static int no_nul_byte = FALSE;
  46. static int reccnt = 0;
  47. static int maxlen = 0;
  48.  
  49. /* functions local to this file */
  50. static void done();
  51. static char **read_args();
  52. static char *build_temp_name();
  53. static void create_database();
  54. static void add_to_database();
  55. static void add_ending_record();
  56. static char *getline();
  57. static void rename_database();
  58.  
  59. /*ARGSUSED*/
  60. void
  61. main(argc, argv)
  62.     int argc;
  63.     char **argv;
  64. {
  65.     char **files;
  66.     char *temp_name;
  67.  
  68.     program = *argv++;
  69.  
  70.     files = read_args(argv);
  71.  
  72.     if (out_name == NULL) {
  73.     if (files[0] && ! EQ(files[0], "-")) {
  74.         out_name = files[0];
  75.     } else {
  76.         out_name = "dbm";
  77.     }
  78.     }
  79.  
  80.     temp_name = build_temp_name(out_name);
  81.     create_database(temp_name);
  82.  
  83.     if (*files) {
  84.     while (*files) {
  85.         FILE *f;
  86.  
  87.         if (EQ(*files, "-")) {
  88.         add_to_database(stdin);
  89.         files++;
  90.         continue;
  91.         }
  92.         f = fopen(*files, "r");
  93.         if (f == NULL) {
  94.         (void) fprintf(stderr, "%s: cannot open ", program);
  95.         (void) perror(*files);
  96.         done(EX_NOINPUT);
  97.         }
  98.         add_to_database(f);
  99.         files++;
  100.     }
  101.     } else {
  102.     add_to_database(stdin);
  103.     }
  104.  
  105.  
  106.     if (ypstamps) {
  107.     add_yp_stamps();
  108.     }
  109.  
  110.     if (! no_at_record) {
  111.     add_ending_record();
  112.     }
  113.  
  114.     rename_database(temp_name, out_name);
  115.  
  116.     if (verbose) {
  117.     (void) printf("Added %d records, longest record was %d bytes\n",
  118.               reccnt, maxlen);
  119.     }
  120.  
  121.     dbmclose();
  122.     exit(EX_OK);
  123. }
  124.  
  125. add_yp_stamps()
  126. {
  127.     datum key_lastmod, val_lastmod;
  128.     datum key_master,  val_master;
  129.     long now;
  130.     char nows[32];
  131.  
  132. #ifdef HAVE_GETHOSTNAME
  133.     char host[256];
  134.  
  135.     if(gethostname(host, sizeof(host)) < 0) {
  136.         done(EX_DATAERR);
  137.     }
  138. #else
  139. #ifdef HAVE_UNAME
  140.     struct utsname utsname;
  141.     char *host;
  142.  
  143.     (void) uname(&utsname);
  144.     host = utsname.nodename;
  145. #else
  146. #ifdef SITENAME_FILE
  147.     char host[4096];
  148.     FILE *f;
  149.     char *p;
  150.  
  151.     f = fopen(SITENAME_FILE, "r");
  152.     if (f == NULL) {
  153.         fprintf(stderr, "%s: cannot open ", program);
  154.         perror(SITENAME_FILE);
  155.         done(EX_OSFILE);
  156.     }
  157.     host[0] = '\0';
  158.     fgets(host, sizeof(host), f);
  159.     if (host[0] == '\0') {
  160.         fprintf(stderr, "%s: no hostname found in %s\n",
  161.             program, SITENAME_FILE);
  162.         exit(EX_OSFILE);
  163.     }
  164.     p = strchr(host, '\n');
  165.     if (p)
  166.         *p = '\0';
  167.     fclose(f);
  168. #else
  169.     fprintf(stderr, "%s: No known method for computing hostname\n",
  170.         program);
  171.     done(EX_USAGE);
  172. #endif    /* SITENAME_FILE */
  173. #endif    /* HAVE_UNAME */
  174. #endif    /* HAVE_GETHOSTNAME */
  175.  
  176.     (void) time(&now);
  177.     sprintf(nows, "%10.10ld", now);
  178.  
  179.     key_lastmod.dptr  = "YP_LAST_MODIFIED";
  180.     key_lastmod.dsize = strlen(key_lastmod.dptr);
  181.     val_lastmod.dptr  = nows;
  182.     val_lastmod.dsize = strlen(val_lastmod.dptr);
  183.  
  184.     key_master.dptr   = "YP_MASTER_NAME";
  185.     key_master.dsize  = strlen(key_master.dptr);
  186.     val_master.dptr   = host;
  187.     val_master.dsize  = strlen(val_master.dptr);
  188.  
  189.     if (store(key_lastmod, val_lastmod) < 0) {
  190.         (void) fprintf(stderr, "%s: store failed for %s\n",
  191.                    program, key_lastmod.dptr);
  192.         done(EX_DATAERR);
  193.     }
  194.  
  195.     if (store(key_master, val_master) < 0) {
  196.         (void) fprintf(stderr, "%s: store failed for %s\n",
  197.                    program, key_master.dptr);
  198.         done(EX_DATAERR);
  199.     }
  200. }
  201.  
  202. /*
  203.  * for errors or signals, remove the temp files
  204.  */
  205. static void
  206. done(ex)
  207.     int ex;
  208. {
  209.     dbmclose();
  210.     (void) unlink(temp_dir);
  211.     (void) unlink(temp_pag);
  212.     exit(ex);
  213. }
  214.  
  215. /*
  216.  * read through the arglist and turn argv into list of input files
  217.  */
  218. static char **
  219. read_args(args)
  220.     char **args;
  221. {
  222.     char **filev = args;
  223.     char **filep = args;
  224.  
  225.     while (*args) {
  226.     if ((*args)[0] == '-' && (*args)[1] != '\0') {
  227.         static char *end_arg = "";
  228.         char *s = &(*args)[1];
  229.  
  230.         while (*s) {
  231.         switch (*s++) {
  232.         case 'y':
  233.             ypstamps = TRUE;
  234.             break;
  235.  
  236.         case 'f':
  237.             downcase = TRUE;
  238.             break;
  239.  
  240.         case 'v':
  241.             verbose = TRUE;
  242.             break;
  243.  
  244.         case 'n':
  245.             no_nul_byte = TRUE;
  246.             break;
  247.  
  248.         case 'd':
  249.             no_at_record = TRUE;
  250.             break;
  251.  
  252.         case 'o':
  253.             if (*s != '\0') {
  254.             out_name = s;
  255.             s = end_arg;
  256.             } else {
  257.             out_name = *++args;
  258.             }
  259.             break;
  260.  
  261.         default:
  262.             (void) fprintf(stderr,
  263.                   "Usage: %s [-yfvnd] [-o database] [file ...]\n",
  264.                    program);
  265.             exit(EX_USAGE);
  266.         }
  267.         }
  268.     } else {
  269.         *filep++ = *args;
  270.     }
  271.     args++;
  272.     }
  273.  
  274.     *filep = NULL;
  275.     return filev;
  276. }
  277.  
  278. /*
  279.  * build a temp filename in the same directory as the given file
  280.  */
  281. static char *
  282. build_temp_name(name)
  283.     char *name;
  284. {
  285.     char *fn;
  286.     char *slash = rindex(name, '/');
  287.     extern char *mktemp();
  288.  
  289.     if (slash) {
  290.     fn = xmalloc((unsigned)(slash - name + sizeof("/dbmXXXXXX")));
  291.     (void) strncpy(fn, name, slash - name);
  292.     (void) strcat(fn, "/dbmXXXXXX");
  293.     } else {
  294.     fn = xmalloc(sizeof("dbmXXXXXX"));
  295.     strcpy(fn, "dbmXXXXXX");
  296.     }
  297.     return mktemp(fn);
  298. }
  299.  
  300. /*
  301.  * create a DBM database with the given basename
  302.  */
  303. static void
  304. create_database(dbm_name)
  305.     char *dbm_name;
  306. {
  307.     int fd;
  308.     int temp_len = strlen(dbm_name);
  309.  
  310.     temp_dir = xmalloc(temp_len + sizeof(".dir"));
  311.     temp_pag = xmalloc(temp_len + sizeof(".pag"));
  312.     (void) sprintf(temp_dir, "%s.dir", dbm_name);
  313.     (void) sprintf(temp_pag, "%s.pag", dbm_name);
  314.  
  315.     fd = creat(temp_dir, 0644);
  316.     if (fd < 0) {
  317.     (void) fprintf(stderr, "%s: cannot creat ", program);
  318.     (void) perror(temp_dir);
  319.     exit(EX_TEMPFAIL);
  320.     }
  321.     (void) close(fd);
  322.  
  323.     fd = creat(temp_pag, 0644);
  324.     if (fd < 0) {
  325.     (void) fprintf(stderr, "%s: cannot creat ", program);
  326.     (void) perror(temp_pag);
  327.     (void) unlink(temp_dir);
  328.     exit(EX_TEMPFAIL);
  329.     }
  330.     (void) close(fd);
  331.  
  332.     /* open the new DBM database */
  333.     if (dbminit(dbm_name) < 0) {
  334.     (void) fprintf(stderr, "%s: dbminit failed ", program);
  335.     (void) perror(dbm_name);
  336.     done(EX_TEMPFAIL);
  337.     }
  338. }
  339.  
  340. /*
  341.  * add all entries in the file to the DBM database
  342.  */
  343. static void
  344. add_to_database(f)
  345.     FILE *f;
  346. {
  347.     register char *s;
  348.  
  349.     while (s = getline(f)) {
  350.     register char *data;
  351.     datum key, content;
  352.  
  353.     for (data = s; *data && *data != ':' && !isspace(*data); data++) ;
  354.  
  355.     if (*data) {
  356.         *data++ = '\0';
  357.         key.dptr = s;
  358.         key.dsize = data - s - 1;
  359.         content.dptr = data;
  360.         content.dsize = strlen(data);
  361.         if (! no_nul_byte) {
  362.         key.dsize++;
  363.         content.dsize++;
  364.         }
  365.         if (downcase) {
  366.         register char *sp;
  367.  
  368.         for (sp = s; *sp; sp++) {
  369.             *sp = lowercase(*sp);
  370.         }
  371.         }
  372.         if (store(key, content) < 0) {
  373.         (void) fprintf(stderr, "%s: store failed for %s\n",
  374.                    program, s);
  375.         done(EX_DATAERR);
  376.         }
  377.         reccnt++;
  378.         if (content.dsize + key.dsize > maxlen) {
  379.         maxlen = content.dsize + key.dsize;
  380.         }
  381.     } else {
  382.         (void) fprintf(stderr, "%s: no value for key %s, ignored\n",
  383.                program, s);
  384.     }
  385.     }
  386. }
  387.  
  388. /*
  389.  * add the ending `@' record, to make sendmail happy.
  390.  */
  391. static void
  392. add_ending_record()
  393. {
  394.     datum key, content;
  395.  
  396.     content.dptr = key.dptr = "@";
  397.     content.dsize = key.dsize = (no_nul_byte? 1: 2);
  398.     if (store(key, content) < 0) {
  399.     (void) fprintf(stderr, "%s: store failed for end record\n", program);
  400.     }
  401. }
  402.  
  403. /*
  404.  * read and return one line from the given file.
  405.  *
  406.  * return NULL on end of input.
  407.  */
  408. static char *
  409. getline(f)
  410.     register FILE *f;
  411. {
  412.     static struct str str;
  413.     static int inited = FALSE;
  414.     register int c;
  415.  
  416.     if (! inited) {
  417.     STR_INIT(&str);
  418.     inited = TRUE;
  419.     } else {
  420.     str.i = 0;
  421.     }
  422.     while ((c = getc(f)) != EOF && c != '\n') {
  423.     STR_NEXT(&str, c);
  424.     }
  425.     if (c == EOF && str.i == 0) {
  426.     return NULL;
  427.     }
  428.     STR_NEXT(&str, '\0');
  429.     return str.p;
  430. }
  431.  
  432. /*
  433.  * rename the database from the old name to a new one.
  434.  *
  435.  * Allow some time after unlinking the old name so that smail will not
  436.  * open the .dir file of the old database and the .pag file of the new
  437.  * one accidentally.
  438.  */
  439. static void
  440. rename_database(from, to)
  441.     char *from;
  442.     char *to;
  443. {
  444.     unsigned int fromlen = (unsigned)strlen(from);
  445.     unsigned int tolen = (unsigned)strlen(to);
  446.     char *from_dir = xmalloc(fromlen + sizeof(".dir"));
  447.     char *from_pag = xmalloc(fromlen + sizeof(".pag"));
  448.     char *to_dir = xmalloc(tolen + sizeof(".dir"));
  449.     char *to_pag = xmalloc(tolen + sizeof(".pag"));
  450.  
  451.     (void) sprintf(from_dir, "%s.dir", from);
  452.     (void) sprintf(from_pag, "%s.pag", from);
  453.     (void) sprintf(to_dir, "%s.dir", to);
  454.     (void) sprintf(to_pag, "%s.pag", to);
  455.  
  456.     (void) unlink(to_dir);
  457.     (void) unlink(to_pag);
  458.     (void) sleep(2);            /* sleep at least 1 second */
  459.     if (link(from_dir, to_dir) < 0) {
  460.     (void) fprintf(stderr, "%s: cannot link %s to ", program, from_dir);
  461.     (void) perror(to_dir);
  462.     done(EX_CANTCREAT);
  463.     }
  464.     if (link(from_pag, to_pag) < 0) {
  465.     (void) fprintf(stderr, "%s: cannot link %s to ", program, from_pag);
  466.     (void) perror(to_pag);
  467.     done(EX_CANTCREAT);
  468.     }
  469.     (void) unlink(from_dir);
  470.     (void) unlink(from_pag);
  471. }
  472.  
  473. /*
  474.  * standalone versions of some referenced routines
  475.  */
  476. char *
  477. xmalloc(len)
  478.     unsigned int len;
  479. {
  480.     char *malloc();
  481.     register char *ret = malloc(len);
  482.  
  483.     if (ret == NULL) {
  484.     (void) fprintf(stderr, "%s: out of memory!\n", program);
  485.     exit(EX_OSERR);
  486.     }
  487.     return ret;
  488. }
  489.  
  490. char *
  491. xrealloc(s, len)
  492.     char *s;
  493.     unsigned int len;
  494. {
  495.     char *realloc();
  496.     register char *ret = realloc(s, len);
  497.  
  498.     if (ret == NULL) {
  499.     (void) fprintf(stderr, "%s: out of memory!\n", program);
  500.     exit(EX_OSERR);
  501.     }
  502.     return ret;
  503. }
  504.